# Web框架使用了基于asyncio的aiohttp，这是基于协程的异步模型。在协程中，不能调用普通的同步IO操作，因为所有用户都是由一个线程服务的，协程的执行速度必须非常快，
# # 才能处理大量用户的请求。而耗时的IO操作不能在协程中以同步的方式调用，否则，等待一个IO操作时，系统无法响应任何其他用户。
# # 这就是异步编程的一个原则：一旦决定使用异步，则系统每一层都必须是异步，“开弓没有回头箭”。
# # 幸运的是aiomysql为MySQL数据库提供了异步IO的驱动。

import logging, aiomysql

# 创建连接池
# 我们需要创建一个全局的连接池，每个HTTP请求都可以从连接池中直接获取数据库连接。使用连接池的好处是不必频繁地打开和关闭数据库连接，而是能复用就尽量复用。
# 连接池由全局变量__pool存储，缺省情况下将编码设置为utf8，自动提交事务：
from leanr_base.case_demo.web_app.util.log import loginfo


# 数据库异步连接池
async def create_pool(loop, **kw):
    logging.info('create database connection pool...')
    global __pool
    __pool = await aiomysql.create_pool(
        host=kw.get('host', 'localhost'),
        port=kw.get('port', 3306),
        user=kw['root'],
        password=kw['123456'],
        db=kw['dbsql'],
        charset=kw.get('charset', 'utf8'),
        autocommit=kw.get('autocommit', True),
        maxsize=kw.get('maxsize', 10),  # minsize(int)最小的池子 ， 反之maxsize(int)
        minsize=kw.get('minsize', 1),
        loop=loop
    )


# Select
# 要执行SELECT语句，我们用select函数执行，需要传入SQL语句和SQL参数：
async def select(sql, args, size=None):
    loginfo('select', sql, args)
    # 声明全局变量
    global __pool
    with (await __pool) as conn:
        # 生成一个游标
        cur = await conn.cursor(aiomysql.DictCursor)
        # 执行sql查询
        await cur.execute(sql.replace('?', '%s'), args or ())
        if size:
            # 限制查询
            rs = await cur.fetchmany(size)
        else:
            # 查询所有
            rs = await cur.fetchall()
        await cur.close()
        logging.info('rows returned: %s' % len(rs))
        return rs


# Insert, Update, Delete 增删改操作
async def executecommon(sql, args):
    loginfo('executecommon', sql, args)
    with (await __pool) as conn:
        try:
            cur = await conn.cursor()
            await cur.execute(sql.replace('?', '%s'), args)
            affected = cur.rowcount
            await cur.close()
        except BaseException as e:
            raise
        return affected
